import asyncio
import json
import os
import time

import tornado.web
import tornado.ioloop
import tornado.httpserver
import tornado.websocket
import redis
import threading

class BaseHandler(tornado.web.RequestHandler):
    # 重写父类方法
    def set_default_headers(self):
        # 设置头部的 跨域 允许链接方法 头部允许参数
        # Access - Control - Allow - Origin
        self.set_header("Access-Control-Allow-Origin", "*")
        self.set_header("Access-Control-Allow-Headers", "x-requested-with")
        self.set_header("Access-Control-Allow-Headers", "x-requested-with, Content-Type, token")
        self.set_header("Access-Control-ALlow-Methods", "POST,GET,DELETE,PUT")
        self.set_header("Content-Type", "application/json; charset=UTF-8")

    def post(self):
        self.write("这里的post请求")

    def get(self):
        self.write("这里的get请求")

    def put(self):
        self.write("这里的ut请求")

    def delete(self):
        self.write("这里的delete请求")

    def options(self, *args):
        # 设置状态码
        self.set_status(204)
        self.finish()

class Msg:
    connect = {}
    connect_id = {}

    def on_connect(self, user, id):
        id = str(id)
        # print(self.connect)
        if id in self.connect_id:
            self.del_connect(user)
        if user in self.connect:
            self.del_connect(user)
        self.connect_id[id] = user
        self.connect[user] = id

    def del_connect(self, user):
        id = self.connect.get(user,"")
        if id:
            del self.connect_id[id]
            del self.connect[user]

    def send(self, id, message):
        id = str(id)
        if id in self.connect_id:
            self.connect_id[id].write_message(message)


# websocket主动推送视图
class WsHandler(tornado.websocket.WebSocketHandler):
    # 跨域
    def check_origin(self, origin: str) -> bool:
        return True

    # 重写链接方法
    def open(self):
        id = self.get_argument("id", None)
        Msg().on_connect(self, id)

    # 重写断开链接方法
    def on_close(self):
        Msg().del_connect(self)

    # 接收信息方法 前端的消息
    async def on_message(self, message):
        self.write_message(message)


# redis监听
from tools import ret_json


def redis_listener(loop):
    asyncio.set_event_loop(loop)
    async def listener():
        # 实例化reids实例
        r = redis.Redis(decode_responses=True, charset="utf-8", encoding="utf-8")
        # 声明pubsub实例
        ps = r.pubsub()
        # 订阅聊天实例
        ps.subscribe("chat")
        # 遍历监听 打印监听到的信息
        for item in ps.listen():
            print(item)
            if "data" in item and item["data"] != 1:
                data = json.loads(item["data"])
                Msg().send(data["cid"],item["data"])
            # data = eval(item["data"])
            # print(data)

    future = asyncio.gather(listener(),)
    loop.run_until_complete(future)


# 发送信息类i
class Send(BaseHandler):
    async def post(self):
        data = self.get_argument("data", None)

        # 实例化reids实例
        r = redis.Redis(decode_responses=True, charset="utf-8", encoding="utf-8")
        # chat发布信息data
        r.publish("chat", data)
        r.rpush("chat",data)
        return self.write(ret_json({"code": 200, "msg": "ok"}))

# 上传文件的接口
class Uploder(BaseHandler):
    async def post(self):
        file = self.request.files["file"]
        type = self.get_argument("type",None)
        new_filename = ""
        for meta in file:
            # 获取文件名
            filename = meta["filename"]
            t = str(int(time.time()))
            last_name = os.path.splitext(filename)[-1]
            new_filename = t+last_name
            with open("./static/"+new_filename,"wb") as f:
                f.write(meta["body"])
        return self.write(ret_json({"code":200,"msg":"上传成功","filename":new_filename}))

# 实例化tornado对象
app = tornado.web.Application(
    handlers=[
        (r"/send/", Send),  # 发送信息
        (r"/ws/", WsHandler), # 建立websocker链接
        (r"/upload/", Uploder), # 上传视频,文件

    ],
    static_path=os.path.join(os.path.dirname(__file__),"static"),
    debug=True
)

if __name__ == '__main__':
    print("chat_main开始了")
    loop = asyncio.new_event_loop()
    # 声明单线程实例
    threading.Thread(target=redis_listener,args=(loop,)).start()
    # 创建聊天服务器
    chat_server = tornado.httpserver.HTTPServer(app, xheaders=True)
    # 服务器的端口
    chat_server.listen(8000)
    # 开启轮询
    tornado.ioloop.IOLoop.instance().start()
